﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace lab04
{
    class HorizontalMatrixGroup : IMatrix
    {
        private readonly List<IMatrix> _matrices;

        private bool CheckIndex(int i, int j)
        {
            return 0 <= i && i < GetNumRows() && 0 <= j && j < GetNumColumns();
        }

        public HorizontalMatrixGroup()
        {
            _matrices = new List<IMatrix>();
        }

        public void SetValue(int i, int j, int value)
        {
            if (!CheckIndex(i, j)) throw new IndexOutOfRangeException();

            int offset = 0;
            int index;

            for (index = 0; index < _matrices.Count; index++)
            {
                if (offset <= j && j < offset + _matrices[index].GetNumColumns()) break;
                offset += _matrices[index].GetNumColumns();
                index++;
            }

            if (i < _matrices[index].GetNumRows())
                _matrices[index].SetValue(i, j - offset, value);
        }


        public int GetValue(int i, int j)
        {
            if (! CheckIndex(i,j) ) throw new IndexOutOfRangeException();

            int offset = 0;
            int index;

            for (index = 0; index < _matrices.Count; index++)
            {
                if (offset <= j && j < offset + _matrices[index].GetNumColumns()) break;
                offset += _matrices[index].GetNumColumns();
                index++;
            }

            if (i >= _matrices[index].GetNumRows())
                return 0;
            return _matrices[index].GetValue(i, j - offset);
        }

        public int GetNumRows()
        {
            if (_matrices != null) return _matrices.Select(matrix => matrix.GetNumRows()).Concat(new[] {0}).Max();
            return 0;
        }

        public int GetNumColumns()
        {
            if (_matrices != null) return _matrices.Select(matrix => matrix.GetNumColumns()).Concat(new[] {0}).Sum();
            return 0;
        }

        public IMatrixIterator GetIterator()
        {
            return new HorizontalMatrixGroupIterator(this);
        }

        public IMatrixIterator GetSubmatrixIterator(int index)
        {
            return _matrices[index].GetIterator();
        }

        public int GetSubmatrixNumColumns(int index)
        {
            return _matrices[index].GetNumColumns();
        }

        public void Add(IMatrix matrix)
        {
            _matrices.Add(matrix);
        }
    }


    class VerticalMatrixGroup : IMatrix
    {
        private readonly List<IMatrix> _matrices;

        private bool CheckIndex(int i, int j)
        {
            return 0 <= i && i < GetNumRows() && 0 <= j && j < GetNumColumns();
        }

        public VerticalMatrixGroup()
        {
            _matrices = new List<IMatrix>();
        }

        public void SetValue(int i, int j, int value)
        {
            if (!CheckIndex(i, j)) throw new IndexOutOfRangeException();

            int offset = 0;
            int index;

            for (index = 0; index < _matrices.Count; index++)
            {
                if (offset <= j && j < offset + _matrices[index].GetNumRows()) break;
                offset += _matrices[index].GetNumRows();
                index++;
            }

            if (i < _matrices[index].GetNumColumns())
                _matrices[index].SetValue(i - offset, j, value);
        }


        public int GetValue(int i, int j)
        {
            if (!CheckIndex(i, j)) throw new IndexOutOfRangeException();

            int offset = 0;
            int index;

            for (index = 0; index < _matrices.Count; index++)
            {
                if (offset <= j && j < offset + _matrices[index].GetNumRows()) break;
                offset += _matrices[index].GetNumRows();
                index++;
            }

            if (i >= _matrices[index].GetNumColumns())
                return 0;
            return _matrices[index].GetValue(i - offset, j);
        }

        public int GetNumRows()
        {
            if (_matrices != null) return _matrices.Select(matrix => matrix.GetNumRows()).Concat(new[] { 0 }).Sum();
            return 0;
        }

        public int GetNumColumns()
        {
            if (_matrices != null) return _matrices.Select(matrix => matrix.GetNumColumns()).Concat(new[] { 0 }).Max();
            return 0;
        }

        public IMatrixIterator GetIterator()
        {
            return new VerticalMatrixGroupIterator(this);
        }

        public IMatrixIterator GetSubmatrixIterator(int index)
        {
            return _matrices[index].GetIterator();
        }

        public int GetSubmatrixNumRows(int index)
        {
            return _matrices[index].GetNumRows();
        }

        public void Add(IMatrix matrix)
        {
            _matrices.Add(matrix);
        }
    }


}
